/*-*-C-*-
 *
 * This file provides a simple mapping from window handles to
 * app-specific data pointers (closures)
 */

#include "resed.h"

#define DELTA 10

typedef struct _registryrec
{
    int used;
    int handle;
    RegistryType type;
    void *closure;
} RegistryRec, *RegistryPtr;

static RegistryPtr list = NULL;
static int listlen = 0;
static int listused = 0;


/*
 * Register a window.  Returns NULL for success, or else
 * an error ptr.
 */

error * registry_register_window (int handle, RegistryType type, void *closure)
{
    if (list)                   /* check for duplicate */
    {
        int i;
        for (i = 0; i < listused; i++)
            if (list[i].used && list[i].handle == handle)
                return NULL;
    }
    if (listused >= listlen)
        list = realloc (list, sizeof(RegistryRec) * (listlen += DELTA));
    if (list == NULL)
    {
        listlen = listused = 0;
        return error_lookup ("NoMem");
    }
    list[listused].used = TRUE;
    list[listused].handle = handle;
    list[listused].type = type;
    list[listused].closure = closure;
    listused++;
    return NULL;
}


/*
 * Deregister a window.  Returns NULL for success, or else
 * an error ptr.
 */

error * registry_deregister_window (int handle)
{
    if (list)
    {
        int i;
        for (i = 0; i < listused; i++)
            if (list[i].used && list[i].handle == handle)
            {
                list[i].used = FALSE;
                if (i == listused - 1)
                    listused--;
                break;
            }
    }
    return NULL;
}


/*
 * Lookup a window based on its handle.  Returns the type,
 * or Unknown if the window was no found.  Note: does
 * not return error ptrs.  Can pass closure == NULL if you
 * don't want to know it.
 */

RegistryType registry_lookup_window (int handle, void **closure)
{
    if (list)
    {
        int i;
        for (i = 0; i < listused; i++)
            if (list[i].used && list[i].handle == handle)
            {
                if (closure) *closure = list[i].closure;
                return list[i].type;
            }
    }
    return Unknown;
}


/*
 * Enumerate.  Returns details of position'th entry, and updates position
 * to next.  (0 -> no more).
 */

int registry_enumerate_windows (int i, RegistryType *type, int *handle, void **closure)
{
    if (!list || listused == 0 || i >= listused)
        return 0;
    if (list[i].used == FALSE)
        return registry_enumerate_windows (i + 1, type, handle, closure);
    if (type) *type = list[i].type;
    if (handle) *handle = list[i].handle;
    if (closure) *closure = list[i].closure;
    return i + 1;
}
